package coc.core.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.apache.commons.lang3.StringUtils;

import com.gargoylesoftware.htmlunit.html.DomNode;

/**
 * HtmlUnit工具类。覆盖了HtmlUnit查询语法中的eq/lt/gt操作符语义，使它符合标准的CSS查询语法。
 */
public class HtmlUnitUtils {
	/**
	 * 从父元素中获取符合CSS查询表达式的子元素集合。
	 * 
	 * @param element
	 *            父元素
	 * @param cssQuery
	 *            CSS查询表达式
	 * @return 返回符合CSS查询表达式的子元素集合。
	 */
	public static List<DomNode> select(DomNode element, String cssQuery) {
		Integer minOpIndex = getMinOpIndex(cssQuery);
		if (minOpIndex != -1) {
			String ps = cssQuery.substring(0, minOpIndex);
			String ns = cssQuery.substring(minOpIndex);
			Integer cursor = ns.indexOf(")") + 1;
			String op = ns.substring(0, cursor);
			ns = ns.substring(cursor);

			List<DomNode> elements = getElements(element, ps, op);
			if (StringUtils.isNotEmpty(ns)) {
				elements = select(elements, ns);
			}
			return elements;
		} else {
			return element.querySelectorAll(cssQuery);
		}
	}

	/**
	 * 从父元素集合中获取符合CSS查询表达式的子元素集合。
	 * 
	 * @param elements
	 *            父元素集合
	 * @param cssQuery
	 *            CSS查询表达式
	 * @return 返回符合CSS查询表达式的子元素集合。
	 */
	public static List<DomNode> select(List<DomNode> elements, String cssQuery) {
		List<DomNode> childElements = new ArrayList<DomNode>();
		for (DomNode element : elements) {
			childElements.addAll(select(element, cssQuery));
		}
		return childElements;
	}

	/**
	 * 从父元素中获取符合CSS查询表达式及操作符的子元素集合。
	 * 
	 * @param element
	 *            父元素
	 * @param cssQuery
	 *            CSS查询表达式
	 * @param operator
	 *            操作符(eq/lt/gt)
	 * @return 返回符合CSS查询表达式及操作符的子元素集合。
	 */
	private static List<DomNode> getElements(DomNode element, String cssQuery,
			String operator) {
		Integer cursor = Integer.valueOf(operator.replaceAll("\\D", ""));
		List<DomNode> elements = new ArrayList<DomNode>();
		if (StringUtils.isNotEmpty(cssQuery)) {
			elements = element.querySelectorAll(cssQuery);
		}
		if (operator.startsWith(":eq")) {
			elements = Arrays.asList(elements.get(cursor));
		}
		if (operator.startsWith(":lt")) {
			elements = new ArrayList<DomNode>(elements.subList(0, cursor));
		}
		if (operator.startsWith(":gt")) {
			elements = new ArrayList<DomNode>(elements.subList(cursor + 1,
					elements.size()));
		}
		return elements;
	}

	/**
	 * 获取CSS查询表达式中第一个的eq/lt/gt函数的开始位置。
	 * 
	 * @param cssQuery
	 *            CSS查询表达式
	 * @return 返回表达式中第一个的eq/lt/gt函数的开始位置。
	 */
	private static Integer getMinOpIndex(String cssQuery) {
		Integer minOpIndex = -1;
		List<Integer> indexs = new ArrayList<Integer>();
		Integer eqIndex = cssQuery.indexOf(":eq");
		if (eqIndex != -1) {
			indexs.add(eqIndex);
		}
		Integer ltIndex = cssQuery.indexOf(":lt");
		if (ltIndex != -1) {
			indexs.add(ltIndex);
		}
		Integer gtIndex = cssQuery.indexOf(":gt");
		if (gtIndex != -1) {
			indexs.add(gtIndex);
		}
		if (!indexs.isEmpty()) {
			Collections.sort(indexs);
			minOpIndex = indexs.get(0);
		}
		return minOpIndex;
	}
}
